using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using FireStarter.CodeGeneration;
using FireStarterModeller.BO;
using NUnit.Framework;

namespace FireStarter.Test.CodeGeneration
{
    [TestFixture]
    public class TestUiProjectGenerator : TestProjectGeneratorBase
    {
        private static UIBaseProjectGenerator CreateUIProjectReadyToGenerate()
        {
            UIBaseProjectGenerator projectGenerator = new UIBaseProjectGenerator();
            CreateSolutionGenerator(projectGenerator);
            projectGenerator.ProjectPath = GetRootedPath(Path.Combine(TEST_PROJECTS_FOLDER, GetRandomString()));
            projectGenerator.ProjectName = "TestProject.UI";
            projectGenerator.ModelSolution.BOProjectName = GetRandomString();
            projectGenerator.ModelSolution.LogicProjectName = GetRandomString();
            return projectGenerator;
        }
        protected override IProjectGenerator CreateProjectReadyToGenerate()
        {
            return CreateUIProjectReadyToGenerate();
        }

        protected override IProjectGenerator CreateProjectGenerator()
        {
            return new UIBaseProjectGenerator();
        }

        private void AssertProjectGeneratedCorrectly(UIBaseProjectGenerator uiBaseProjectGenerator, ProjectFileManager boProjectFileManager, ProjectFileManager logicProjectFileManager)
        {
            string libFolderName = uiBaseProjectGenerator.SolutionGenerator.HabaneroReferencePath;
            libFolderName = Utilities.GetRelativePath(libFolderName, uiBaseProjectGenerator.ProjectPath);
            string projectFileName = uiBaseProjectGenerator.ProjectFileName;
            Assert.IsTrue(Directory.Exists(uiBaseProjectGenerator.ProjectPath));
            Assert.IsTrue(File.Exists(projectFileName));
            ProjectFileManager projectFileManager = new ProjectFileManager(projectFileName, CodeTemplateEnum.CSharpVisualStudio2005);
            Assert.AreEqual(OutputType.Library, projectFileManager.OutputType);
            string projectFileContents = File.ReadAllText(projectFileName);
            StringAssert.Contains("<Compile Include=\"UIManager.cs\" />", projectFileContents);
            StringAssert.Contains(@"<Compile Include=""Properties\AssemblyInfo.cs"" />", projectFileContents);
            AssertHasProjectReference(projectFileContents, uiBaseProjectGenerator, boProjectFileManager);
            if (logicProjectFileManager != null)
            {
                AssertHasProjectReference(projectFileContents, uiBaseProjectGenerator, logicProjectFileManager);
            }
            AssertHasReference(projectFileContents, string.Format(@"{0}\Habanero.Base.dll", libFolderName));
            AssertHasReference(projectFileContents, string.Format(@"{0}\Habanero.BO.dll", libFolderName));
            AssertHasReference(projectFileContents, string.Format(@"{0}\Habanero.Faces.Base.dll", libFolderName));
            AssertHasNotReference(projectFileContents, string.Format(@"{0}\Habanero.Util.dll", libFolderName));
        }

        [Test]
        public void TestCreateUiProjectGenerator()
        {
            //---------------Set up test pack-------------------
            
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            IProjectGenerator projectGenerator = CreateProjectGenerator();
            //---------------Test Result -----------------------
            Assert.IsNotNull(projectGenerator);
            Assert.IsInstanceOf(typeof(UIBaseProjectGenerator), projectGenerator);
        }

        [Test]
        public void TestBoProjectReference()
        {
            //---------------Set up test pack-------------------
            string boProjectName = GetRandomString();
            UIBaseProjectGenerator projectGenerator = new UIBaseProjectGenerator();
            projectGenerator.SolutionGenerator = new SolutionGenerator();
            projectGenerator.SolutionGenerator.ModelSolution = new DMSolution();
            //---------------Assert Precondition----------------
            Assert.IsNull(projectGenerator.ModelSolution.BOProjectName);
            //---------------Execute Test ----------------------
            projectGenerator.ModelSolution.BOProjectName = boProjectName;
            //---------------Test Result -----------------------
            Assert.AreEqual(boProjectName, projectGenerator.ModelSolution.BOProjectName);
        }

        [Test]
        public void TestGenerate_Fails_BoProjectReferenceNotSet()
        {
            //---------------Set up test pack-------------------
            UIBaseProjectGenerator projectGenerator = CreateUIProjectReadyToGenerate();
            projectGenerator.ModelSolution.BOProjectName = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(projectGenerator.ModelSolution.BOProjectName);
            //---------------Execute Test ----------------------
            Exception exception = null;
            try
            {
                projectGenerator.Generate();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            //---------------Test Result -----------------------
            Assert.IsNotNull(exception, "Exception Expected");
            Assert.IsInstanceOf(typeof(ReferenceMissingException), exception);
            ReferenceMissingException referenceMissingException = (ReferenceMissingException)exception;
            Assert.AreEqual("BOProjectName", referenceMissingException.ReferenceName);
        }

        [Test]
        public void TestLogicProjectReference()
        {
            //---------------Set up test pack-------------------
            string logicProjectName = GetRandomString();
            UIBaseProjectGenerator projectGenerator = new UIBaseProjectGenerator();
            projectGenerator.SolutionGenerator = new SolutionGenerator();
            projectGenerator.SolutionGenerator.ModelSolution = new DMSolution();
            //---------------Assert Precondition----------------
            Assert.IsNull(projectGenerator.ModelSolution.LogicProjectName);
            //---------------Execute Test ----------------------
            projectGenerator.ModelSolution.LogicProjectName = logicProjectName;
            //---------------Test Result -----------------------
            Assert.AreEqual(logicProjectName, projectGenerator.ModelSolution.LogicProjectName);
        }

        [Test]
        public void TestGenerate_DoesNotFail_IfLogicProjectMissing()
        {
            //---------------Set up test pack-------------------

            UIBaseProjectGenerator projectGenerator = CreateUIProjectReadyToGenerate();
            projectGenerator.ModelSolution.LogicProjectName = null;
            ProjectFileManager boProjectFileManager = CreateRandomProjectFile(projectGenerator.ModelSolution.BOProjectName);
            //---------------Assert Precondition----------------
            Assert.IsFalse(File.Exists(projectGenerator.ProjectFileName));
            //---------------Execute Test ----------------------
            projectGenerator.Generate();
            //---------------Test Result -----------------------
            AssertProjectGeneratedCorrectly(projectGenerator, boProjectFileManager, null);
        }

        [Test]
        public void TestGenerate_Creates_ProjectFile_IfDoesNotExist()
        {
            //---------------Set up test pack-------------------
            UIBaseProjectGenerator projectGenerator = CreateUIProjectReadyToGenerate();

            ProjectFileManager boProjectFileManager = CreateRandomProjectFile(projectGenerator.ModelSolution.BOProjectName);
            ProjectFileManager logicProjectFileManager = CreateRandomProjectFile(projectGenerator.ModelSolution.LogicProjectName);
            //---------------Assert Precondition----------------
            Assert.IsFalse(File.Exists(projectGenerator.ProjectFileName));
            //---------------Execute Test ----------------------
            projectGenerator.Generate();
            //---------------Test Result -----------------------
            AssertProjectGeneratedCorrectly(projectGenerator, boProjectFileManager, logicProjectFileManager);
        }

        [Test]
        public void Test_GenerateIControlFactory_DualWINVWG_ReturnsTrue()
        {
            //---------------Set up test pack-------------------
            UIBaseProjectGeneratorSpy projectGenerator = new UIBaseProjectGeneratorSpy();
            projectGenerator.SolutionGenerator = new SolutionGenerator();
            projectGenerator.SolutionGenerator.SolutionTypeName = GenerationTypes.SOLUTION_TYPE_DUALWINVWG;
            //---------------Assert Precondition----------------
            Assert.AreEqual(GenerationTypes.SOLUTION_TYPE_DUALWINVWG, projectGenerator.SolutionGenerator.SolutionTypeName);
            //---------------Execute Test ----------------------
            bool actualGenerateControlFactory = projectGenerator.CallGenerateIControlFactory();
            //---------------Test Result -----------------------
            Assert.IsTrue(actualGenerateControlFactory);
        }

        [Test]
        public void Test_GenerateIControlFactory_Other_ReturnsFalse()
        {
            //---------------Set up test pack-------------------
            UIBaseProjectGeneratorSpy projectGenerator = new UIBaseProjectGeneratorSpy();
            projectGenerator.SolutionGenerator = new SolutionGenerator();
            projectGenerator.SolutionGenerator.SolutionTypeName = GenerationTypes.SOLUTION_TYPE_VWG;
            //---------------Assert Precondition----------------
            Assert.AreEqual(GenerationTypes.SOLUTION_TYPE_VWG, projectGenerator.SolutionGenerator.SolutionTypeName);
            //---------------Execute Test ----------------------
            bool actualGenerateControlFactory = projectGenerator.CallGenerateIControlFactory();
            //---------------Test Result -----------------------
            Assert.IsFalse(actualGenerateControlFactory);
        }

        [Test]
        public void TestGenerate_AddsIControlFactory_IfDualWINVWG()
        {
            //---------------Set up test pack-------------------
            UIBaseProjectGenerator projectGenerator = CreateUIProjectReadyToGenerate();
            projectGenerator.SolutionGenerator.SolutionTypeName = GenerationTypes.SOLUTION_TYPE_DUALWINVWG;
            //---------------Assert Precondition----------------
            Assert.AreEqual(GenerationTypes.SOLUTION_TYPE_DUALWINVWG, projectGenerator.SolutionGenerator.SolutionTypeName);
            //---------------Execute Test ----------------------
            projectGenerator.Generate();
            //---------------Test Result -----------------------
            string projectFileContents = File.ReadAllText(projectGenerator.ProjectFileName);
            string controlFactoryName = "I"+projectGenerator.SolutionGenerator.ModelSolution.ApplicationName + "ControlFactory.cs";
            StringAssert.Contains(@"<Compile Include=""" + controlFactoryName + @""" />", projectFileContents);
        }

         [Test]
        public void TestGenerate_DoesNotAddIControlFactory_IfOther()
        {
            //---------------Set up test pack-------------------
            UIBaseProjectGenerator projectGenerator = CreateUIProjectReadyToGenerate();
            projectGenerator.SolutionGenerator.SolutionTypeName = GenerationTypes.SOLUTION_TYPE_VWG;
            //---------------Assert Precondition----------------
            Assert.AreEqual(GenerationTypes.SOLUTION_TYPE_VWG, projectGenerator.SolutionGenerator.SolutionTypeName);
            //---------------Execute Test ----------------------
            projectGenerator.Generate();
            //---------------Test Result -----------------------
            string projectFileContents = File.ReadAllText(projectGenerator.ProjectFileName);
            string controlFactoryName = "I"+projectGenerator.SolutionGenerator.ModelSolution.ApplicationName + "ControlFactory.cs";
            Assert.IsFalse(projectFileContents.Contains(@"<Compile Include=""" + controlFactoryName + @""" />"));
        }

        public abstract class TestUIProjectGenerator_GeneratedFile : TestProjectGeneratorBase_GeneratedFile
        {
            protected override IProjectGenerator CreateProjectReadyToGenerate()
            {
                return CreateUIProjectReadyToGenerate();
            }
        }

        public class TestUIProjectGenerator_GeneratedFile_UIManager : TestUIProjectGenerator_GeneratedFile
        {
            protected override string GetFileName()
            {
                return "UIManager.cs";
            }

            protected override void AssertFileGeneratedCorrectly(IProjectGenerator projectGenerator, string fileContents)
            {
                UIBaseProjectGenerator uiBaseProjectGenerator = (UIBaseProjectGenerator) projectGenerator;
                ProjectFileManager projectFileManager = new ProjectFileManager(uiBaseProjectGenerator.ModelSolution.BOProjectName, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
                TestUiProjectTemplateLoader.AssertUiManagerCorrect(fileContents, uiBaseProjectGenerator.ProjectName, projectFileManager.AssemblyName);
            }
        }
    }

    public class UIBaseProjectGeneratorSpy : UIBaseProjectGenerator
    {
        public bool CallGenerateIControlFactory()
        {
            return base.GenerateIControlFactory();
        }
    }
}
